package org.jeecg.modules.manage.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.boot.starter.rabbitmq.client.RabbitMqClient;
import org.jeecg.cmbCloudDirectLink.model.PullAccountModel;
import org.jeecg.cmbCloudDirectLink.model.PushAccountModel;
import org.jeecg.cmbCloudDirectLink.utils.CMBApi;
import org.jeecg.common.api.dto.BankSetDTO;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.manage.entity.*;
import org.jeecg.modules.manage.mapper.MCaishuiTaskSettleItemMapper;
import org.jeecg.modules.manage.mapper.MCaishuiTaskSettleMapper;
import org.jeecg.modules.manage.service.*;
import org.jeecg.modules.manage.vo.ServiceFeeVo;
import org.omg.CosNaming.BindingHelper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @Description: 任务结算
 * @Author: yfkj
 * @Date:   2023-02-20
 * @Version: V1.0
 */
@Service
@Slf4j
public class MCaishuiTaskSettleServiceImpl extends ServiceImpl<MCaishuiTaskSettleMapper, CaishuiTaskSettle> implements IMCaishuiTaskSettleService {

    @Resource
    private MCaishuiTaskSettleItemMapper mCaishuiTaskSettleItemMapper;
    @Autowired
    private IMCaishuiBusinessBankService imCaishuiBusinessBankService;
    @Autowired
    private IMCaishuiTaskSettleListService imCaishuiTaskSettleListService;
    @Autowired
    private IMCaishuiInternalTransferService imCaishuiInternalTransferService;
    @Autowired
    private IMCaishuiWithdrawService imCaishuiWithdrawService;
    @Resource
    private IMCaishuiCompanySetService imCaishuiCompanySetService;
    @Autowired
    private RabbitMqClient rabbitMqClient;
    @Autowired
    private RedisUtil redisUtil;
    @Resource
    private ISysBaseAPI iSysBaseAPI;

    /**
     * 任务结算--下发
     * @param caishuiTaskSettle
     */
    @Override
    public Result<?> doSubmit(CaishuiTaskSettle caishuiTaskSettle, BankSetDTO bankSetDTO){
        /**1、更新任务结算*/
        caishuiTaskSettle.setStatus(2);
        caishuiTaskSettle.setExtendStatus(1);
        caishuiTaskSettle.setExtendTime(new Date());
        caishuiTaskSettle.setCheckTime(new Date());

        /**2、代发*/
        //付款方
        PushAccountModel pushAccountModel = new PushAccountModel();
        pushAccountModel.setAccount(caishuiTaskSettle.getPayAccount());
        pushAccountModel.setName(caishuiTaskSettle.getPayName());
        pushAccountModel.setSubUnit(caishuiTaskSettle.getPaySubUnit());
        pushAccountModel.setTotalAmount(caishuiTaskSettle.getTotalAmount().toString());
        pushAccountModel.setTotalNum(caishuiTaskSettle.getTotalNum().toString());
        pushAccountModel.setOrderNo(caishuiTaskSettle.getOrderNo());
        pushAccountModel.setExpectDate(DateUtils.sdf8.format(new Date()));
        //任务结算详情列表
        List<CaishuiTaskSettleItem> itemList = mCaishuiTaskSettleItemMapper.selectByMainId(caishuiTaskSettle.getId());
        if(oConvertUtils.listIsEmpty(itemList)){
            return Result.error("任务详情为空！");
        }
        //收款方
        List<PullAccountModel> pullList = new ArrayList<>();
        for (CaishuiTaskSettleItem taskSettleItem : itemList) {
            PullAccountModel pullAccountModel = new PullAccountModel();
            BeanUtils.copyProperties(taskSettleItem, pullAccountModel);
            pullList.add(pullAccountModel);
        }

        //代发
        Result df_result = CMBApi.doIssuedOnBehalf(pushAccountModel,pullList, bankSetDTO);
        log.info("=======代发结果=========》》》：" + df_result);
        if(df_result.isSuccess()){
            //处理代发成功后的事件
            JsonObject object = new GsonBuilder().create().fromJson(df_result.getResult().toString(), JsonObject.class);
            caishuiTaskSettle.setBankReqnbr(object.get("reqnbr").getAsString());
            caishuiTaskSettle.setBankReqsta(object.get("reqsta").getAsString());
            caishuiTaskSettle.setExtendTime(new Date());
            this.baseMapper.updateById(caishuiTaskSettle);
            return Result.ok("下发成功，请耐心等待银行处理！");
        }else {
            log.error("银企直连代发失败：" + df_result.getMessage());
            return Result.error("下发失败，失败原因：" + df_result.getMessage());
        }
    };

    /**
     *  处理代发批次与明细查询事件
     *  批次与明细查询
     * @param orderNo 订单编号（业务参考号）
     */
    @Override
    @Transactional
    public void handleTaskSettle(String orderNo){
        //查询任务结算信息
        CaishuiTaskSettle caishuiTaskSettle = this.baseMapper.queryTaskSettleByOrderNo(orderNo);
        if(oConvertUtils.isEmpty(caishuiTaskSettle) || oConvertUtils.isEmpty(caishuiTaskSettle.getId())){
            return;
        }
        //查询任务结算详情列表
        List<CaishuiTaskSettleItem> itemList = mCaishuiTaskSettleItemMapper.selectByMainId(caishuiTaskSettle.getId());
        if(oConvertUtils.listIsEmpty(itemList)){
            return;
        }
        //根据账号查询服务公司设置相关信息
        BankSetDTO bankSetDTO = imCaishuiCompanySetService.queryCompanySet(caishuiTaskSettle.getPayAccount());

        /**1、代发批次与明细查询*/
        Result mxcx_result = CMBApi.queryBatchAndDetail(caishuiTaskSettle.getOrderNo(), bankSetDTO);
        log.info("------------mxcx_result------------------:" + mxcx_result);
        if(mxcx_result.isSuccess()){
            JsonObject jsonObject = new GsonBuilder().create().fromJson(mxcx_result.getResult().toString(), JsonObject.class);
            //批次信息（单记录）：批次信息中，reqsta =’FIN’表示银行已经处理完成，rtnflg =’F’，表示整批交易失败，
            // rtnflg =”S”表示整批交易全部成功或者部分成功（rsv100第1位为“P”时表示部分成功）
            JsonObject bb6bpdqyz1 = jsonObject.getAsJsonArray("bb6bpdqyz1").get(0).getAsJsonObject();
            log.info("------------bb6bpdqyz1------------------:" + bb6bpdqyz1);
            String reqsta = bb6bpdqyz1.get("reqsta").getAsString();//业务请求状态
            String rtnflg = bb6bpdqyz1.get("rtnflg").getAsString();//业务请求结果
            String sucnum = bb6bpdqyz1.get("sucnum").getAsString();//成功笔数
            String sucamt = bb6bpdqyz1.get("sucamt").getAsString();//成功金额
            String stscod = oConvertUtils.isEmpty(bb6bpdqyz1.get("stscod")) ? "" : bb6bpdqyz1.get("stscod").getAsString();//记录状态
            String errcod = oConvertUtils.isEmpty(bb6bpdqyz1.get("errcod")) ? "" : bb6bpdqyz1.get("errcod").getAsString();//错误码
            String errdsp = oConvertUtils.isEmpty(bb6bpdqyz1.get("errdsp")) ? "" : bb6bpdqyz1.get("errdsp").getAsString();//错误描述

            /**2、更新业务结算*/
            caishuiTaskSettle.setBankReqsta(reqsta);
            caishuiTaskSettle.setBankRtnflg(rtnflg);
            caishuiTaskSettle.setSuccessNum(oConvertUtils.getInt(sucnum,0));
            caishuiTaskSettle.setSuccessAmount(BigDecimal.valueOf(oConvertUtils.getDouble(sucamt,0.00)));
            caishuiTaskSettle.setBankStscod(stscod);
            caishuiTaskSettle.setBankErrcod(errcod);
            caishuiTaskSettle.setBankErrdsp(errdsp);
            int failNum = caishuiTaskSettle.getTotalNum() - caishuiTaskSettle.getSuccessNum();
            BigDecimal failAmount = caishuiTaskSettle.getTotalAmount().subtract(caishuiTaskSettle.getSuccessAmount()).setScale(2,BigDecimal.ROUND_HALF_UP);
            if("F".equals(rtnflg)){//整批交易失败
                caishuiTaskSettle.setFailNum(failNum);
                caishuiTaskSettle.setFailAmount(failAmount);
                caishuiTaskSettle.setExtendStatus(3);
            }else if("S".equals(rtnflg)){//整批交易全部成功或者部分成功
                caishuiTaskSettle.setFailNum(failNum);
                caishuiTaskSettle.setFailAmount(failAmount);
                caishuiTaskSettle.setExtendStatus(2);
            }
            caishuiTaskSettle.setExtendTime(new Date());

            /**3、更新业务结算详情*/
            BigDecimal successServiceFee = new BigDecimal(0.00);//成功下发服务费
            JsonArray bb6bpdqyz2 = jsonObject.getAsJsonArray("bb6bpdqyz2");//批次明细信息
            log.info("------------bb6bpdqyz2------------------:" + bb6bpdqyz2);
            for (JsonElement jsonElement : bb6bpdqyz2) {
                JsonObject item = jsonElement.getAsJsonObject();
                String item_accnbr = item.get("accnbr").getAsString();//账号
                String item_accnam = item.get("accnam").getAsString();//户名
                String item_stscod = oConvertUtils.isEmpty(item.get("stscod")) ? "" : item.get("stscod").getAsString();//交易状态
                String item_errcod = oConvertUtils.isEmpty(item.get("errcod")) ? "" : item.get("errcod").getAsString();;//失败代码
                String item_errtxt = oConvertUtils.isEmpty(item.get("errtxt")) ? "" : item.get("errtxt").getAsString();//失败原因
                for (CaishuiTaskSettleItem taskSettleItem : itemList) {
                    if(taskSettleItem.getMainId().equals(caishuiTaskSettle.getId()) && taskSettleItem.getName().trim().equals(item_accnam.trim())
                            && taskSettleItem.getBankCard().trim().equals(item_accnbr.trim())){
                        taskSettleItem.setBankFeedbackStscod(item_stscod);
                        taskSettleItem.setBankFeedbackCode(item_errcod);
                        taskSettleItem.setBankFeedbackMessage(item_errtxt);
                        taskSettleItem.setBankFeedbackTime(new Date());
                        if("S".equals(item_stscod)){//成功
                            taskSettleItem.setStatus(2);
                            successServiceFee = successServiceFee.add(new BigDecimal(taskSettleItem.getServiceFee())).setScale(2,BigDecimal.ROUND_HALF_UP);
                        }else if("E".equals(item_stscod)){//失败
                            taskSettleItem.setStatus(3);
                        }else {
                            taskSettleItem.setStatus(1);
                        }
                        taskSettleItem.setIssuedTime(new Date());
                        mCaishuiTaskSettleItemMapper.updateById(taskSettleItem);
                    }
                }
            }
            caishuiTaskSettle.setSuccessServiceFee(successServiceFee.doubleValue());

            //已发放==>处理事件
            if(caishuiTaskSettle.getExtendStatus()==2){
//                /**3、记账子单元内部转账：服务费转入账号对应的税费子账户*/
//                //查询当前账号下的税费子账户
//                CaishuiBusinessBank businessBank = imCaishuiBusinessBankService.getOne(new LambdaQueryWrapper<CaishuiBusinessBank>()
//                        .eq(CaishuiBusinessBank::getServiceCompanyId,caishuiTaskSettle.getCompanyId()).eq(CaishuiBusinessBank::getType,2));
                /**4、记账子单元内部转账：服务费转入账号对应的默认子账户（招商银行银企直联会有一个默认子账户000000）*/
                //转账
                Result zz_result = CMBApi.doInternalTransfer(caishuiTaskSettle.getPayAccount(),caishuiTaskSettle.getPaySubUnit(),
                        "000000",caishuiTaskSettle.getSuccessServiceFee().toString(),"服务费", bankSetDTO);
                if(zz_result.isSuccess()){
                    /**5、新增记账子单元内部转账记录*/
                    JsonArray ntdmatrxz1 = new GsonBuilder().create().fromJson(zz_result.getResult().toString(), JsonArray.class);
                    log.info("------------ntdmatrxz1------------------:" + ntdmatrxz1);
                    for (JsonElement jsonElement : ntdmatrxz1) {
                        CaishuiInternalTransfer internalTransfer = new CaishuiInternalTransfer();
                        internalTransfer.setCompanyId(caishuiTaskSettle.getCompanyId());
                        internalTransfer.setBusinessId(caishuiTaskSettle.getBusinessId());
                        internalTransfer.setTenantId(caishuiTaskSettle.getTenantId());
                        internalTransfer.setOrderNo(caishuiTaskSettle.getOrderNo());
                        internalTransfer.setTrxdat(jsonElement.getAsJsonObject().get("trxdat").getAsString());
                        internalTransfer.setAccnbr(jsonElement.getAsJsonObject().get("accnbr").getAsString());
                        internalTransfer.setDmanbr(jsonElement.getAsJsonObject().get("dmanbr").getAsString());
                        internalTransfer.setTrxnbr(jsonElement.getAsJsonObject().get("trxnbr").getAsString());
                        internalTransfer.setTrxamt(jsonElement.getAsJsonObject().get("trxamt").getAsString());
                        internalTransfer.setTrxdir(jsonElement.getAsJsonObject().get("trxdir").getAsString());
                        imCaishuiInternalTransferService.save(internalTransfer);
                    }
                }else {
                    caishuiTaskSettle.setExtendStatus(4);//记账子单元内部转账失败
                    log.error("【"+orderNo+"】记账子单元内部转账失败[服务费]：" + zz_result.getMessage());
//                    throw new JeecgBootException("下发失败！");
                }
            }

            /**6、新增提现记录*/
            if("FIN".equals(reqsta)){//reqsta =’FIN’表示银行已经处理完成
                for (CaishuiTaskSettleItem taskSettleItem : itemList) {
                    CaishuiWithdraw withdraw = new CaishuiWithdraw();
                    BeanUtils.copyProperties(taskSettleItem, withdraw);
                    withdraw.setCompanyId(caishuiTaskSettle.getCompanyId());
                    withdraw.setBusinessId(caishuiTaskSettle.getBusinessId());
                    withdraw.setUserId(caishuiTaskSettle.getUserId());
                    withdraw.setChannelBusinessId(caishuiTaskSettle.getChannelBusinessId());
                    withdraw.setOrderNo(caishuiTaskSettle.getOrderNo());
                    withdraw.setPayName(caishuiTaskSettle.getPayName());
                    withdraw.setPayAccount(caishuiTaskSettle.getPayAccount());
                    withdraw.setPaySubUnit(caishuiTaskSettle.getPaySubUnit());
                    withdraw.setType(1);
                    withdraw.setBankChannel("银企直联");
                    imCaishuiWithdrawService.save(withdraw);
                }
            }

            /**7、新增业务结算清单*/
            if("S".equals(rtnflg)){//rtnflg =”S”表示整批交易全部成功或者部分成功
                CaishuiTaskSettleList settleList = new CaishuiTaskSettleList();
                settleList.setCompanyId(caishuiTaskSettle.getCompanyId());
                settleList.setBusinessId(caishuiTaskSettle.getBusinessId());
                settleList.setTenantId(caishuiTaskSettle.getTenantId());
                settleList.setSettleId(caishuiTaskSettle.getId());
                settleList.setSettleName(caishuiTaskSettle.getName());
                settleList.setSuccessAmount(caishuiTaskSettle.getSuccessAmount());
                settleList.setSuccessNum(caishuiTaskSettle.getSuccessNum());
                settleList.setSettleDoc(caishuiTaskSettle.getSettleDoc());
                settleList.setSettleStatus(caishuiTaskSettle.getExtendStatus());
                settleList.setSettleCreateTime(caishuiTaskSettle.getCreateTime());
                settleList.setSettleSubmitTime(caishuiTaskSettle.getSubmitTime());
                imCaishuiTaskSettleListService.save(settleList);
            }
        }

        //更新代发任务
        this.baseMapper.updateById(caishuiTaskSettle);
        log.info("~~~~~~~~~~~~成功！~~~~~~~~~~~~~~");
    };

    /**
     * 计算下发服务费
     * @param idCard
     * @param amount
     * @param taxRate
     * @param taxRateTwo
     * @return
     */
    @Override
    public Result<ServiceFeeVo> handleServiceFee(String idCard, Double amount, Double taxRate, Double taxRateTwo) {
        ServiceFeeVo serviceFeeVo = new ServiceFeeVo();
        double serviceFee = 0.00;//服务费
        double serviceFeeDiffer = 0.00;//服务费差额（一档税率到二档税率）
        //一档税率到二档税率差
        BigDecimal taxRateDiffer = BigDecimal.valueOf(taxRateTwo).subtract(BigDecimal.valueOf(taxRate)).setScale(4, BigDecimal.ROUND_HALF_UP);
        //如果税率差小于等于0，则直接计算服务费之后返回
        if (taxRateDiffer.doubleValue() <=0) {
            //服务费 = 下发金额 * 一档费率
            serviceFee = BigDecimal.valueOf(amount).multiply(BigDecimal.valueOf(taxRate)).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            serviceFeeVo.setServiceFee(serviceFee);
            serviceFeeVo.setServiceFeeDiffer(0.00);
            return Result.ok(serviceFeeVo);
        }

        //税率临界值，默认3万
        double taxRateValue = oConvertUtils.getDouble(iSysBaseAPI.queryValueByCode("A05B01"), 30000.00);
        //查询用户本月已下发总额
        double issuedAmountTotal = mCaishuiTaskSettleItemMapper.getIssuedAmountTotal(idCard);
        /**
         * 判断本月已下发总额是否大于等于税率临界值
         * 1、如果大于等于税率临界值，则直接按二挡税率计算服务费
         * 2、如果小于税率临界值，再判断 （本月已下发总额 + 本次下发金额）是否大于等于税率临界值
         *    a、如果大于等于税率临界值，则直接按二挡税率计算服务费，并补回原来的服务费差额
         *    b、如果小于税率临界值，则直接按一档税率计算服务费，并计算服务费差额
         */
        if (issuedAmountTotal >= taxRateValue) {
            serviceFee = BigDecimal.valueOf(amount).multiply(BigDecimal.valueOf(taxRateTwo)).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            serviceFeeDiffer = 0.00;
        } else {
            if ((issuedAmountTotal + amount) >= taxRateValue) {
                //本月服务费差额总额
                double serviceFeeDifferTotal = mCaishuiTaskSettleItemMapper.getServiceFeeDifferTotal(idCard);
                //本次服务费按二挡税率计算
                BigDecimal fee = BigDecimal.valueOf(amount).multiply(BigDecimal.valueOf(taxRateTwo)).setScale(2, BigDecimal.ROUND_HALF_UP);
                //服务费 = 本月服务费差额总额 + 本次服务费
                serviceFee = BigDecimal.valueOf(serviceFeeDifferTotal).add(fee).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                serviceFeeDiffer = 0.00;
            } else {
                //服务费 = 下发金额 * 一档费率
                serviceFee = BigDecimal.valueOf(amount).multiply(BigDecimal.valueOf(taxRate)).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                //服务费差额
                serviceFeeDiffer = BigDecimal.valueOf(amount).multiply(taxRateDiffer).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            }
        }
        //返回服务费信息
        serviceFeeVo.setServiceFee(serviceFee);
        serviceFeeVo.setServiceFeeDiffer(serviceFeeDiffer);
        return Result.ok(serviceFeeVo);
    };

}
